package cn.practice.chat.config;

import cn.practice.chat.security.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @ClassName Security过滤器  5.7之后不用集成WebSecurityConfigurerAdapter
 * Spring Security 就不需要再去重写 configure() 方法了，直接通过 filterChain() 方法就能使用 HttpSecurity 来配置相关信息
 * @Description:
 * @Author A-TAO
 * @Date 2022/10/19
 * @Version V1.0
 **/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    @Autowired
    private LoginFailureHanlder loginFailureHanlder;

    @Autowired
    private LoginSuccessHanlder loginSuccessHanlder;

    @Autowired
    private CaptchaFilter captchaFilter;


    @Autowired
    private AuthenticationFailedHanlder authenticationFailedHanlder;

    @Autowired
    private AccessRefuseHandler accessRefuseHandler;

    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 注入AuthenticationConfiguration
     */
    @Autowired
    private AuthenticationConfiguration auth;

    @Autowired
    private LogoutSuccessHandler logoutSuccessHandler;


    /**
     * 编写AuthenticationManager的bean
     */
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return auth.getAuthenticationManager();
    }


    @Bean
    TokenAuthenticationFilter jwtAuthenticationFilter() throws Exception {
        TokenAuthenticationFilter tokenAuthenticationFilter = new TokenAuthenticationFilter(authenticationManager());
        return tokenAuthenticationFilter;
    }


    // url 白名单不用验证
    private static  final String[] URL_WHITELIST = {
           "/login",
            "/regist",
            "/feign/*",
            "/logout",
            "/captcha",
            "/sys-user/list/pass",
            "/uploadFile",
            "/favicon.ico",
            "/swagger**/**",
            "/swagger-ui.html",
            "/swagger-resources/**",
            "/qiniu/upload"
    };


//    @Bean
//    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
//        return authenticationConfiguration.getAuthenticationManager();
//    }


//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.userDetailsService()
//    }

    /**
     * 替换旧版本中的configure(HttpSecurity http)方法
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws  Exception{
        // 基于 token，不需要 csrf
        http.cors().and().csrf().disable();
        http.httpBasic()
                // 基于 token，不需要 session
                .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

                // 过滤
                .and()
                    .authorizeRequests()
                    // 放开的请求
                    .antMatchers(URL_WHITELIST)
                    .permitAll()
                    // 其他地址的访问均需验证权限
                    .anyRequest().authenticated()
                .and()
                    .formLogin()
                    .successHandler(loginSuccessHanlder)
                    .failureHandler(loginFailureHanlder)
                .and()
                    .logout().logoutUrl("/logout")
                    //登出处理
                    .addLogoutHandler(logoutSuccessHandler)
                // 异常处理

                .and()
                    .exceptionHandling()
                    .authenticationEntryPoint(authenticationFailedHanlder)
                    .accessDeniedHandler(accessRefuseHandler)
                // 自定义过滤器
                .and().addFilter(jwtAuthenticationFilter())
                // 验证码验证
                .addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)
                .userDetailsService(userDetailsService);
                //回话管理 //同一账号同时登录最大用户数
//                .sessionManagement()
//                .maximumSessions(1)
//                // 会话信息过期策略会话信息过期策略(账号被挤下线)
//                .expiredSessionStrategy(customizeSessionInformationExpiredStrategy);


        return http.build();
    }





    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }

}
